package com.brillilab.service.logic.instrument;

import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.entity.ResponseVo;
import com.brillilab.common.exceptions.BrillilabException;
import com.brillilab.common.utils.TimeUtil;
import com.brillilab.domain.enums.common.BoolEnum;
import com.brillilab.domain.enums.instrument.AppointmentStateEnum;
import com.brillilab.domain.enums.instrument.CancelTypeEnum;
import com.brillilab.domain.po.instrument.Instrument;
import com.brillilab.domain.po.instrument.InstrumentAppointment;
import com.brillilab.domain.po.instrument.InstrumentMaintenance;
import com.brillilab.domain.vo.instrument.MaintenanceVo;
import com.brillilab.domain.vo.instrument.SchedulerEventVo;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.instrument.IInstrumentAppointmentService;
import com.brillilab.service.core.instrument.IInstrumentMaintenanceService;
import com.brillilab.service.core.instrument.IInstrumentService;
import com.brillilab.service.logic.instrument.converter.MaintenanceConverter;
import com.brillilab.service.logic.user.UsersLogic;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Service
@Transactional
public class MaintenanceLogic {

    @Resource
    private IInstrumentMaintenanceService maintenanceService;
    @Resource
    private IInstrumentAppointmentService appointmentService;
    @Resource
    private IInstrumentService instrumentService;
    @Resource
    private InstrumentLogic instrumentLogic;
    @Resource
    private UsersLogic usersLogic;
    @Resource
    private AppointmentLogic appointmentLogic;

    /**
     * 添加维护
     *
     * @param maintenanceVos
     */
    public void addMaintenance(Long instrumId,List<MaintenanceVo> maintenanceVos,UserInfoVo userInfo) {

        Instrument instrument=instrumentService.selectById(instrumId);
        Assert.isTrue(instrument!=null && instrument.getIsDelete().equals(BoolEnum.FALSE.getValue()),"仪器不存在！");
        if(!instrumentLogic.isManagerAndDuty(instrument.getDutyId(),userInfo)){
            throw new BrillilabException(ResultEnum.USER_NOT_POWER);
        }

        // 对象转换
        List<InstrumentMaintenance> maintenances=MaintenanceConverter.maintenanceVoListToMaintenanceList(maintenanceVos);

        List<InstrumentAppointment> appointments=appointmentService.selectList(instrumId,AppointmentStateEnum.NOT_START.getValue());

        List<InstrumentMaintenance> exist=maintenanceService.selectList(instrumId);

        for (InstrumentMaintenance maintenance : maintenances) {

            Assert.isTrue(exist.size() < 3,"已存在3个维护，无法继续添加！");

            //不能与已有维护重复
            if(isMaintenanceCoinsident(maintenance,exist)){
                throw new BrillilabException(ResultEnum.DATA_ALREADY_EXIST);
            }

            maintenance.setInstrumId(instrumId);

            //(2)插入维护信息
            maintenanceService.insert(maintenance);

            //(3)取消维护期间所有预约通知用户
            if(!CollectionUtils.isEmpty(appointments)){
                cancelAllCoincidentAppointments(instrument,maintenance,appointments,userInfo);
            }
        }
    }

    //判断维护是否重叠
    private boolean isMaintenanceCoinsident(InstrumentMaintenance maintenance,List<InstrumentMaintenance> maintenances){
        if(!CollectionUtils.isEmpty(maintenances)){

            for (InstrumentMaintenance e:maintenances){

                //每周维护
                if (e.getType()==0){
                    if(maintenance.getType()==0){
                        if (TimeUtil.isCoincidence(maintenance.getStartDay(),maintenance.getEndDay(),e.getStartDay(),e.getEndDay())){
                            if(TimeUtil.isCoincidence(maintenance.getStartTime(),e.getStartTime(),maintenance.getEndTime(),e.getEndTime()))
                                return true;
                        }
                    }
                }
                //每月维护
                if (e.getType()==1){
                    if(maintenance.getType()==1){
                        if (TimeUtil.isCoincidence(maintenance.getStartDay(),maintenance.getEndDay(),e.getStartDay(),e.getEndDay())){
                            if(TimeUtil.isCoincidence(maintenance.getStartTime(),e.getStartTime(),maintenance.getEndTime(),e.getEndTime()))
                                return true;
                        }
                    }
                }
                //每年维护
                if(e.getType()==2){
                    if(maintenance.getType()==2){
                        if(TimeUtil.isCoincidence(maintenance.getStartMonth(),maintenance.getEndMonth(),e.getStartMonth(),e.getEndMonth())){
                            if (TimeUtil.isCoincidence(maintenance.getStartDay(),maintenance.getEndDay(),e.getStartDay(),e.getEndDay())){
                                if(TimeUtil.isCoincidence(maintenance.getStartTime(),e.getStartTime(),maintenance.getEndTime(),e.getEndTime()))
                                    return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    private void cancelAllCoincidentAppointments(Instrument instrument,InstrumentMaintenance maintenance,List<InstrumentAppointment> appointments,UserInfoVo userInfo){

        for (InstrumentAppointment appointment:appointments){
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(appointment.getStartTime());
            int year = calendar.get(Calendar.YEAR);
            int month = calendar.get(Calendar.MONTH)+1;
            int date = calendar.get(Calendar.DATE);
            int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)-1;

            if(maintenanceService.compareMaintenanceWhitAppointment(appointment,year,month,date,dayOfWeek,maintenance)){
                cancelAppointment(instrument,appointment,userInfo);
            }
        }
    }

    //取消维护期间所有预约通知用户
    @Async
    public void cancelAppointment(Instrument instrument,InstrumentAppointment appointment,UserInfoVo userInfo){
        //取消预约
        appointment.setState(AppointmentStateEnum.CANCEL.getValue());
        appointment.setCancelReason(CancelTypeEnum.ADMIN_CANCEL.getValue());
        appointmentService.updateById(appointment);

        //TODO 通知预约人预约被管理员取消
        sendCancelAppointmentMessage(CancelTypeEnum.ADMIN_CANCEL.getValue(),userInfo,instrument,appointment);
    }

    public void sendCancelAppointmentMessage(Integer reason,UserInfoVo userInfo,Instrument instrument,InstrumentAppointment appointment) {

        UserInfoVo apUser=usersLogic.getUserInfo(userInfo.getLabId(),appointment.getUserId());
        Assert.notNull(apUser,"仪器预约用户不存在于该实验室！");

        appointmentLogic.sendCancelAppointmentMessage(reason,instrument,appointment,apUser);
    }

    /**
     * 删除维护
     * @param instrumId
     * @param id
     * @return
     */
    public boolean deleteMaintanence(Long instrumId,Long id,UserInfoVo userInfo) {

        Instrument instrument=instrumentService.selectById(instrumId);
        Assert.isTrue(instrument!=null && instrument.getIsDelete().equals(BoolEnum.FALSE.getValue()),"仪器不存在！");
        if(!instrumentLogic.isManagerAndDuty(instrument.getDutyId(),userInfo)){
            throw new BrillilabException(ResultEnum.USER_NOT_POWER);
        }

        InstrumentMaintenance exist = maintenanceService.selectById(id);
        Assert.notNull(exist,"维护信息不存在！");


        return maintenanceService.deleteById(id);
    }

    /**
     * 日历插件中显示维护
     * @param instrumId
     * @return
     */
    public List<SchedulerEventVo> getMaintenanceEventList(Long instrumId) {

        List<InstrumentMaintenance> maintenances=maintenanceService.selectList(instrumId);

        return MaintenanceConverter.maintenanceListToSchadularEventVoList(maintenances);
    }
}
